package game.dungeon;

import game.dungeon.position.Coordinate;
import game.dungeon.position.CoordinateType;
import game.dungeon.position.Direction;
import game.dungeon.position.Position;
import game.square.Door;
import game.square.Rock;
import game.square.SquareImpl;
import be.kuleuven.cs.som.annotate.Basic;
import be.kuleuven.cs.som.annotate.Immutable;
/**
 * A class of shafts as a special type of singular dungeons.
 * 
 * @version 1.0
 * @author Chris Desomer, Geert Heyman
 */
public class Shaft <S extends SquareImpl> extends SingularDungeon<S> {
	
	/**
	 * Initialize a new shaft.
	 * 
	 * @param 	boundaryPosition
	 * 			The boundary position for this shaft.
	 * @param 	fixedCoordinates
	 * 			The fixed coordinates for this shaft.
	 * @pre		The given boundary position must be effective.
	 * 		  | boundaryPosition != null
	 * @pre		..
	 * 		  | ( fixedCoordinates != null && fixedCoordinates.length == 3 && fixedCoordinates[0] == null
	 *		  |		&& fixedCoordinates[1] != null && fixedCoordinates[2] != null)
	 * @effect	..
	 * 		  | super(boundaryPosition)
	 * @post	..
	 * 		  | new.getFixedCoordinates().equals(fixedCoordinates)
	 * 
	 */
	public Shaft(Position boundaryPosition, Coordinate[] fixedCoordinates) {
		super(boundaryPosition);
		assert ( fixedCoordinates != null && fixedCoordinates.length == 3 && fixedCoordinates[0] == null
	 		&& fixedCoordinates[1] != null && fixedCoordinates[2] != null);
		this.FIXED_COORDINATES = fixedCoordinates;
	}
	
	/**
	 * Return the fixed coordinates of this shaft.
	 */
	@Basic
	@Immutable
	public Coordinate[] getFixedCoordinates(){
		return FIXED_COORDINATES;
	}
	
	/**
	 * Variable referencing the two fixed coordinates of this shaft.
	 */
	private final Coordinate[] FIXED_COORDINATES;

	/**
	 * Check if this shaft can have the given position as one
	 * of its positions to hold a square
	 * 
	 * @param	position
	 * 			The position to check.
	 * @return	..
	 * 		  | if (!super.canHaveAsPosition(position))
	 * 		  |		then result == false
	 * @result	..
	 * 		  | if (!(position.getCoordinate(getFixedCoordinates[1].getCoordinateType()) == 
	 *		  |	  getFixedCoordinates[1].getCoordinateValue()))
	 *		  |		then result == false
	 * @result	..
	 * 		  | else if (!(position.getCoordinate(getFixedCoordinates[2].getCoordinateType()) == 
	 *		  |   getFixedCoordinates[2].getCoordinateValue()))
	 *		  |		then result == false
	 * @result	..
	 * 		  | else result == true		
	 */
	@Override
	public boolean canHaveAsPosition(Position position) {
		if (!super.canHaveAsPosition(position))
			return false;
		if (!(position.getCoordinate(FIXED_COORDINATES[1].getCoordinateType()) == 
			FIXED_COORDINATES[1].getCoordinateValue()))
			return false;
		if (!(position.getCoordinate(FIXED_COORDINATES[2].getCoordinateType()) == 
			FIXED_COORDINATES[2].getCoordinateValue()))
			return false;
		return true;
	}
	
	/**
	 * Check if this shaft can have the given square at the given position
	 * as one of its square.
	 * 
	 * @param	square
	 * 			The square to check
	 * @param	position
	 * 			The position to check the square at.
	 * @return	..
	 * 		  | if (super.canHaveAsSquareAtPosition(square, position))
	 * 		  |		then result == false
	 * @result	..
	 * 		  |	if (square instanceof Rock)
	 * 		  |		then result == false
	 * @result	..
	 * 		  |	if (square.getBorderInDirection(getFreeCoordinate().getPositiveDirection()) instanceof Door
	 *		  |		|| square.getBorderInDirection(getFreeCoordinate().getPositiveDirection().getOppositeDirection()) 
	 *		  |			instanceof Door)
	 *		  |		then result == false
	 * @result	..
	 * 		  | else result == true
	 */
	@Override
	public boolean canHaveAsSquareAtPosition(S square, Position position) {
		if (!super.canHaveAsSquareAtPosition(square, position))
			return false;
		if (square instanceof Rock)
			return false;
		 Direction oneFreeDirection = getFreeCoordinate().getPositiveDirection();
		 Direction otherFreeDirection = oneFreeDirection.getOppositeDirection();
		if (square.getBorderInDirection(oneFreeDirection) instanceof Door
				|| square.getBorderInDirection(otherFreeDirection) instanceof Door)
			 return false;
		return true;
	}
	
	/**
	 * Get the free coordinate of this shaft.
	 * 
	 * @return	..
	 * 		  | if (getFixedCoordinates()[1].getCoordinateType() != CoordinateType.XCOORDINATE
	 * 		  |		&& getFixedCoordinates()[2].getCoordinateType() != CoordinateType.XCOORDINATE)
	 * 		  |		then result == CoordinateType.XCOORDINATE
	 * @result	..
	 * 		  | if (getFixedCoordinates()[1].getCoordinateType() != CoordinateType.YCOORDINATE
	 * 		  |		&& getFixedCoordinates()[2].getCoordinateType() != CoordinateType.YCOORDINATE)
	 * 		  |		then result ==  CoordinateType.YCOORDINATE
	 * @result	..
	 * 		  | else result ==  CoordinateType.ZCOORDINATE
	 * 
	 */
	public CoordinateType getFreeCoordinate(){
		if (getFixedCoordinates()[1].getCoordinateType() != CoordinateType.XCOORDINATE
				&& getFixedCoordinates()[2].getCoordinateType() != CoordinateType.XCOORDINATE)
			return CoordinateType.XCOORDINATE;
		if (getFixedCoordinates()[1].getCoordinateType() != CoordinateType.YCOORDINATE
				&& getFixedCoordinates()[2].getCoordinateType() != CoordinateType.YCOORDINATE)
			return CoordinateType.YCOORDINATE;
		return CoordinateType.ZCOORDINATE;
	}

}
